const { Token, TokenType } = require('./token.js')
const { log, isSpace, isAuto, isDigit, isKeywordChar } = require('./utils')
const Code = require('./code')
const TokenList = require('./tokenList')


const tokenizer = function(code) {
    let codeString = new Code(code)
    let ts = []
    while (codeString.hasChar()) {
        let c = codeString.peekChar()
        if (isDigit(c)) {
            let n = codeString.readNumber()
            let t = new Token(n, TokenType.number)
            ts.push(t)
        } else if (c === '"') {
            let s = codeString.readString()
            let t = new Token(s, TokenType.string)
            ts.push(t)
        } else if (isAuto(c)) {
            let t = new Token(codeString.readChar(), TokenType.auto)
            ts.push(t)
        } else if (isSpace(c)) {
            // 跳过空白字符
            codeString.readChar()
        } else if (isKeywordChar(c)) {
            let keyword = codeString.readKeyword()
            let t = new Token(keyword, TokenType.keyword)
            ts.push(t)
        } else {
            throw new Error("wrong char", c)
        }
    }
    return ts
}


const parseList = (tokenList) => {
    const tl = tokenList
    let l = []
    while (tl.hasToken()) {
        let t = tl.readToken()
        // 读到 ]，说明读到了末尾了，退出循环返回
        if (t.type === TokenType.bracketRight) {
            break
        // 读到 { , 说明值是个对象，要调用 parseDict 来解析
        } else if (t.type === TokenType.bracketLeft) {
            let a = parseList(tl)
            l.push(a)
        // 读到 [, 说明值是个对象，递归调用 parseDict 解析
        } else if (t.type === TokenType.braceLeft) {
            let o = parseDict(tl)
            l.push(o)
        // 下面都是简单类型，直接 push 到数组中
        } else if (t.type === TokenType.string) {
            l.push(t.value)
        } else if (t.type === TokenType.number) {
            l.push(t.value)
        } else if (t.type === TokenType.boolean) {
            l.push(t.value)
        } else if (t.type === TokenType.null) {
            l.push(t.value)
        // 读到 , 说明后面还有值，继续循环
        } else if (t.type === TokenType.comma) {
            continue
        } else {
            throw new SyntaxError(`Unexpected token ${t.value}`)
        }
    }
    return l
}
const parseDict = (tokenList) => {
    const tl = tokenList
    let o = {}
    while (tl.hasToken()) {
        // 读取 key
        let t1 = tl.readToken()
        // 看一下是不是 }，是的话说明是空对象，直接就返回了
        if (t1.type === TokenType.braceRight) {
            return o
        }
        // 读 冒号 ：
        let t2 = tl.readToken()
        // 读 value 值
        let t3 = tl.readToken()
        let key = t1.value
        // t3 是个 {，说明是 value 是个对象，要递归调用 parseDict 解析对象
        if (t3.type === TokenType.braceLeft) {
            let value = parseDict(tl)
            o[key] = value
        // t3 是个 [，说明 value 值是数组，要调用 parseList 解析数组
        } else if (t3.type === TokenType.bracketLeft) {
            let value = parseList(tl)
            o[key] = value
        // 以下是简单类型，读了直接赋值
        } else if (t3.type === TokenType.null) {
            o[key] = t3.value
        } else if (t3.type === TokenType.number) {
            o[key] = t3.value
        } else if (t3.type === TokenType.string) {
            o[key] = t3.value
        } else if (t3.type === TokenType.boolean) {
            o[key] = t3.type
        } else {
            throw new SyntaxError(`Unexpected token ${t.value}`)
        }
        // 再读一个 token ，看看是不是 , 或者 { 
        // 读到 , ，说明后面还有值，继续循环
        // 读到 } ，说明读到了对象的末尾了，要推出循环返回解析得到的对象
        let t = tl.readToken()
        if (t.type === TokenType.comma) {
            continue
        } else if (t.type === TokenType.braceRight) {
            break
        } else {
            throw new SyntaxError(`Unexpected token ${t.value}`)
        }
    }
    return o
}

const parse = code => {
    let tokens = tokenizer(code)
    let tl = new TokenList(tokens)
    while (tl.hasToken()) {
        let t = tl.readToken()
        if (t.type === TokenType.braceLeft) {
            return parseDict(tl)
        } else if (t.type === TokenType.bracketLeft) {
            return parseList(tl)
        } else {
            throw new SyntaxError(`Unexpected token ${t.value}`)
        }
    }
}
module.exports = {
    parse,
    tokenizer,
}